#include <crt_threadpool.h>
#include <crt_memory.h>

static void do_work(void* arg) {

	//c_assert(arg);

	io_thread_t* p = (io_thread_t*)(arg);
	_threadpool_t* pool = (_threadpool_t*)(p->parent_context);

	if (pool->func.start) {
		pool->func.start(pool, p);
	}

	//Send Sem
	if (p->func.work) {
		_sem_post(&pool->sem);
		p->func.work(pool, p);
	}
	
	if (p->func.stop) {
		p->func.stop(pool, p);
		_sem_post(&pool->sem);
	}
		
}

static int thread_init(_threadpool_t* pool, io_thread_t* thread, void* ctx,int id) {

	rc_assert(thread && pool, S_ERROR)
	
	thread->ctx = ctx;
	thread->parent_context = pool;
	thread->func.start = pool->func.start;
	thread->func.work = pool->func.work;
	thread->func.stop = pool->func.stop;
	thread->func.error = pool->func.error;
	thread->id = id;

	return S_SUCCESS;
}
static int thread_start(io_thread_t* thread) {
	rc_assert(thread, S_ERROR)
	return _thread_create(&thread->threadhandler, do_work, thread);
}
static int thread_stop(io_thread_t* thread) {

	rc_assert(thread, S_ERROR)
	return _thread_join(&thread->threadhandler);
}

int start_threadpool(_threadpool_t* pool) {


	unsigned long iloop = 0;
	rc_assert(pool, S_ERROR);

	for (iloop = 0; iloop < pool->count; iloop++) {
		thread_start(pool->threads + iloop);
	}

	for (iloop = 0; iloop < pool->count; iloop++) {
		_sem_wait(&pool->sem);
	}

	_sem_wait(&pool->exit);

	return S_SUCCESS;
}
int stop_threadpool(_threadpool_t* pool) {

	unsigned long iloop = 0;

	rc_assert(pool, S_ERROR);
	//Create several threads to send signals several times, and wait for a few signals here
	for (iloop = 0; iloop < pool->count; iloop++) {
		_sem_wait(&pool->sem);
	}

	for (iloop = 0; iloop < pool->count; iloop++) {
		thread_stop(pool->threads + iloop);
	}

	_sem_post(&pool->exit);


	return S_SUCCESS;
}
int	uinit_threadpool(_threadpool_t* pool) {

	_sem_destroy(&pool->exit);

	_sem_destroy(&pool->sem);

	if (pool->threads)
		heap_free(pool->threads);

	return S_SUCCESS;
}

int	init_threadpool(_threadpool_t*pool) {

	unsigned int iloop = 0;

	rc_assert(_sem_init(&pool->sem, 0) == 0, S_ERROR)

	rc_assert(_sem_init(&pool->exit, 0) == 0, S_ERROR)

	pool->threads = (io_thread_t*)heap_malloc(pool->count * sizeof(io_thread_t));

	rc_assert(pool != NULL, S_ERROR)


	for (iloop = 0; iloop < pool->count; iloop++) {
		thread_init(pool, pool->threads + iloop, pool->threads, iloop);
	}

	return S_SUCCESS;
}
